package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanException;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 查询资源列表
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstant.RESOURCE_LIST ,key ="#resourceDto.hashCode()")
    public List<ResourceVo> selectList(ResourceDto resourceDto) {
        List<Resource> result = resourceMapper.list(resourceDto);
        return BeanUtil.copyToList(result, ResourceVo.class);
    }

    /**
     * 查询资源树
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstant.RESOURCE_TREE )
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        ResourceDto build = ResourceDto.builder()
                //启用状态
                .dataState(SuperConstant.DATA_STATE_0)
                //父节点id
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))
                //资源类型为菜单
                .resourceType(SuperConstant.MENU)
                .build();
        //所有资源数据  启用的该节点下的所有菜单数据
        List<Resource> list = resourceMapper.list(build);
        //未查到数据
        if (EmptyUtil.isNullOrEmpty(list)) {
            throw new RuntimeException("没有查询到资源数据");
        }
        //构建树形目录  父节点信息
        Resource rootResource = new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        rootResource.setResourceName("智慧养老院");
        //需要放进去的集合容器
        List<TreeItemVo> itemVoList = new ArrayList<>();
        //递归封装
        recursionTreeItem(itemVoList, rootResource, list);
        return TreeVo.builder().items(itemVoList).build();
    }

    /**
     * 创建资源
     *
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)
    })
    public void addResource(ResourceDto resourceDto) {
        //1.根据父id查询父状态
        Resource parentResource = resourceMapper.selectByParentResourceNo(resourceDto.getParentResourceNo());
        //2.拷贝准备插入的属性到实体
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //3.设置插入的状态
        resource.setDataState(parentResource.getDataState());
        //判断当前是否是菜单，不是菜单不需要限制菜单层级
        Boolean flag = true;
        if (!SuperConstant.MENU.equals(resourceDto.getResourceType())) {
            //不是菜单，则不需要限制菜单层级
            flag = false;
        }
        //4.根据父资源编号生成当前资源编号
        String parentResourceResourceNo = parentResource.getResourceNo();
        //4.1是否大于三级菜单
        // 100 001 001 001 001
        if (flag && NoProcessing.processString(parentResourceResourceNo).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //4.2是否已经包含子菜单
        ResourceDto build = ResourceDto.builder()
                .parentResourceNo(parentResourceResourceNo)
                .build();
        //根据父资源编号看能否查到数据
        List<Resource> list = resourceMapper.list(build);
        if (EmptyUtil.isNullOrEmpty(list)) {
            //没有子资源
            String no = NoProcessing.createNo(NoProcessing.processString(parentResourceResourceNo), false);
            resource.setResourceNo(no);
        } else {
            //有子资源
            Long maxNo = list.stream()
                    //得到每一个资源编号，数值型
                    .map(r -> {
                        return Long.valueOf(r.getResourceNo());
                    })
                    //得到最大的一个资源编号
                    .max(Comparator.comparing(i -> i)).get();
            resource.setResourceNo(NoProcessing.createNo(String.valueOf(maxNo), true));
        }
        //插入数据
        resourceMapper.insert(resource);

    }

    /**
     * 修改
     *
     * @param resourceDto
     */
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)
    })
    @Override
    public void updateResource(ResourceDto resourceDto) {
        //准备要修改的资源
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //判断是否三级菜单
        Boolean flag = true;
        if (!SuperConstant.MENU.equals(resourceDto.getResourceType())) {
            //不是菜单，则不需要限制菜单层级
            flag = false;
        }
        if (flag && NoProcessing.processString(resourceDto.getParentResourceNo()).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //根据父id查父里面有的所有数据id+1   （得到最新的资源号）
        ResourceDto build = ResourceDto.builder()
                .parentResourceNo(NoProcessing.processString(resourceDto.getParentResourceNo()))
                .build();
        List<Resource> list = resourceMapper.list(build);
        if (EmptyUtil.isNullOrEmpty(list)) {
            //没有子资源
            resource.setResourceNo(NoProcessing.createNo(resourceDto.getParentResourceNo(), false));
        } else {
            //有子资源
            Long maxNo = list.stream()
                    //得到每一个资源编号，数值型
                    .map(r -> {
                        return Long.valueOf(r.getResourceNo());
                    })
                    //得到最大的一个资源编号
                    .max(Comparator.comparing(i -> i)).get();
            resource.setResourceNo(NoProcessing.createNo(String.valueOf(maxNo), true));
        }

        //当前的资源号作为子的新资源号
        String resourceNo = resource.getResourceNo();
        String s = NoProcessing.processString(resourceNo);
        build.setParentResourceNo(NoProcessing.processString(resourceDto.getResourceNo()));
        List<Resource> son = resourceMapper.list(build);

        for (Resource r : son) {
            String parentResourceNo = r.getParentResourceNo();
            String substring = parentResourceNo.substring(s.length());
            //新的前缀 + 旧的后缀
            r.setParentResourceNo(s + substring);
            resourceMapper.update(r);
        }
        resourceMapper.update(resource);

    }

    /**
     * 状态修改
     *
     * @param resourceDto
     */
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)
    })
    @Override
    public void enableResource(ResourceDto resourceDto) {

        String state = resourceDto.getDataState();
        if (state.equals("0")) {
            //当前是要启用，判断父是否为禁用，父禁用不允许启用
            Resource resource = resourceMapper.selectByParentResourceNo(resourceDto.getParentResourceNo());
            if (resource != null && resource.getDataState().equals("1")) {
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
            // 还要同时启用子菜单
            ResourceDto build = ResourceDto.builder()
                    .parentResourceNo(NoProcessing.processString(resourceDto.getResourceNo()))
                    .build();
            //查询所有子菜单
            List<Resource> list = resourceMapper.list(build);
            if(list != null && list.size() > 0){
                for (Resource resource1 : list) {
                    resource1.setDataState("0");
                    resourceMapper.updateState(resource1);
                }
            }
            resourceMapper.updateState(resource);
        } else {
            //禁用  还要禁用子菜单
            ResourceDto res = ResourceDto.builder()
                    .parentResourceNo(NoProcessing.processString(resourceDto.getResourceNo()))
                    .build();
            List<Resource> list = resourceMapper.list(res);
            if (list != null && list.size() > 0) {
                for (Resource resource1 : list) {
                    resource1.setDataState("1");
                    resourceMapper.updateState(resource1);
                }
            }
            Resource bean = BeanUtil.toBean(resourceDto, Resource.class);
            resourceMapper.updateState(bean);

        }

    }

    /**
     * 删除
     *
     * @param resourceNo
     */
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)
    })
    @Override
    public void deleteResource(String resourceNo) {

    }

    /**
     * @param itemVoList   需要放进去的集合容器
     * @param rootResource 父节点信息
     * @param list         所有集合信息
     */
    private void recursionTreeItem(List<TreeItemVo> itemVoList, Resource rootResource, List<Resource> list) {
        TreeItemVo build = TreeItemVo.builder()
                .id(rootResource.getResourceNo())
                .label(rootResource.getResourceName()).build();
        //获取当前资源下的子资源
        List<Resource> collect = list.stream().filter(n -> n.getParentResourceNo().equals(rootResource.getResourceNo()))
                .collect(Collectors.toList());
        //如果有子资源，进行递归
        if (!EmptyUtil.isNullOrEmpty(collect)) {
            List<TreeItemVo> listChildren = new ArrayList<>();
            collect.forEach(resource -> {
                recursionTreeItem(listChildren, resource, list);
            });
            //将子资源添加
            build.setChildren(listChildren);
        }
        //添加到集合
        itemVoList.add(build);
    }



    /**
     * 根据用户id查询对应的资源数据
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if (CollUtil.isEmpty(menuVoList)) {
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组（parentNo:[{},{}]）
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        menuVoList.forEach(menuVo -> {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/"+menuVo.getName());
            //根据父编号到map中查找是否包含子菜单，如果包含则设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(menuVos)){
                menuVos.forEach(m->{
                    m.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
                    m.setRedirect(m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        });
        //根据根编号查找所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }
}
